package pl.edu.utp.ga.genotypes;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import pl.edu.utp.calculations.Range;
import pl.edu.utp.ga.interfaces.Calculation;
import pl.edu.utp.ga.interfaces.Gene;
import pl.edu.utp.ga.interfaces.Genotype;

public abstract class BasicGenotype implements Genotype{
	
	protected static final int DEFAULT_GENOTYPE_SIZE = 2;
	
	protected ArrayList<Gene<?>> genes;
	protected int size;
	protected Random random;
	protected ArrayList<Range> genesRanges;
	
	public BasicGenotype(){
		this(DEFAULT_GENOTYPE_SIZE);
	}
	
	public BasicGenotype(int size){
		this.size = size;
		genes = new ArrayList<Gene<?>>(size);
		random = new Random();
		//generate();
	}
	
	public BasicGenotype(ArrayList<Gene<?>> genes){
		size = genes.size();
		this.genes = genes;
		random = new Random();
	}
	
	@Override
	public void addGene(Gene<?> gene) {
		genes.add(gene);
		size++;
	}

	@Override
	public void setGene(Gene<?> gene, int position) {
		try{
			gene = genes.set(position, gene);
		}catch(IndexOutOfBoundsException ex){	
			return;
		}
	}

	@Override
	public void removeGene(Gene<?> gene) {
		genes.remove(gene);
	}

	@Override
	public Gene<?> getGene(int position) {
		Gene<?> gene;
		try{
			gene = genes.get(position);
		}catch(IndexOutOfBoundsException ex){
			return null;
		}
		return gene;
	}

	@Override
	public ArrayList<Gene<?>> getGenes() {
		return genes;
	}
	
	@Override
	public ArrayList<Range> getGenesRanges() {
		return genesRanges;
	}

	@Override
	public void setGenesRanges(List<Range> ranges) {
		this.genesRanges = (ArrayList<Range>)ranges;
	}

	protected int getSplitPoint(){
		return random.nextInt(size-1)+1;
	}
	
	protected int genePosition(){
		return random.nextInt(size-1);
	}
	
	public String toString(){
		String text = "";
		for(Gene<?> gene: genes){
			text = String.format("%s %s", text, gene);
		}
		return String.format("%s", text);
	}
		
	@SuppressWarnings("rawtypes")
	@Override
	public abstract ArrayList<Genotype> cross(List<? extends Gene> genes);
	
	@Override
	public abstract void generate();
	
	@Override
	public abstract void mutate();
	
	@Override
	public abstract double rate(Calculation calculation);
}
